﻿using System.Diagnostics;
using System.Text.RegularExpressions;
using DimensionsHelper.Common.Utils;
using DimensionsHelper.LanguageService.Symbols;
using DimensionsHelper.LanguageService.Syntax;

namespace DimensionsHelper.LanguageService;

/// <summary>
///     绑定元数据中的各种符号。包含所有继承<see cref="MetadataSymbol" />的符号类型，
///     包括：元数据Areal定义、字段定义、分类列表定义、页面定义以及属性、样式等详细定义。
/// </summary>
public sealed partial class MetadataBinder(WorkFolder workFolder) : Binder(workFolder)
{
    private static readonly Dictionary<string, SyntaxKinds> EffectiveDbColumnProperties =
        new(StringComparer.OrdinalIgnoreCase)
        {
            { "ID", SyntaxKinds.String },
            { "Label", SyntaxKinds.String },
            { "KeyCode", SyntaxKinds.String },
            { "File", SyntaxKinds.String },
            { "AnalysisValue", SyntaxKinds.String },
            { "Fixed", SyntaxKinds.String },
            { "Exclusive", SyntaxKinds.String }
        };


    private static readonly Dictionary<string, SyntaxKinds> EffectiveDbProperties =
        new(StringComparer.OrdinalIgnoreCase)
        {
            { "ConnectionString", SyntaxKinds.String },
            { "Table", SyntaxKinds.String },
            { "SQLFilter", SyntaxKinds.String },
            { "CacheTimeout", SyntaxKinds.Integer },
            { "IteratorIDType", SyntaxKinds.String },
            { "MinAnswers", SyntaxKinds.Integer },
            { "MaxAnswers", SyntaxKinds.Integer }
        };

    private MetadataArealSymbol? _currentAreal;
    private DomainSymbolTable? _currentFieldDomain;
    private AnalysisTree? _currentTree;

    private string _docContext = string.Empty;
    private string _docLabelType = string.Empty;
    private string _docLanguage = string.Empty;
    private AnalysisTreeSymbolTable? _treeSymbolTable;


    /// <summary>
    ///     设置当前元数据使用的默认用户上下文、语言和标签类型定义名。
    ///     一般情况下，此处设置的应当是Metadata()区间内定义内容。
    ///     在未指定区间标签时，将使用此处定义的类型存储描述、属性、模板等符号。
    /// </summary>
    /// <param name="context">用户上下文类型</param>
    /// <param name="language">语言类型</param>
    /// <param name="labelType">标签类型名</param>
    public void SetContext(string context, string language, string labelType)
    {
        _docContext = context;
        _docLanguage = language;
        _docLabelType = labelType;
    }


    private void CheckDbProperties(MetadataFieldSymbol ownerField,
        IEnumerable<MetadataProperty> properties,
        Dictionary<string, SyntaxKinds> checkDict)
    {
        foreach (MetadataProperty property in properties)
        {
            if (!checkDict.TryGetValue(property.Name, out SyntaxKinds kind))
            {
                Raise(DiagnosticDescriptors.InvalidMetadataDatabasePropertyName,
                    property.NameIdentifier, property.Name);
                continue;
            }

            Expression? value = property.Value;
            // 跳过空值
            if (Expression.IsEmptyExpression(value))
            {
                continue;
            }

            // 只支持常量表达式
            if (!SyntaxFacts.IsLiteralKind(value.Kind))
            {
                Raise(DiagnosticDescriptors.MetadataPropertyOnlySupportConstant, value);
                continue;
            }

            ExpressionConverter converter = ExpressionConverter.SelectConverter(value.Kind);
            if (!converter.TryConvert(value, kind, out Expression? result))
            {
                Raise(DiagnosticDescriptors.CannotConvertTypeImplicitly, value,
                    SyntaxFacts.ConvertTokenToString(kind), SyntaxFacts.ConvertTokenToString(value.Kind));
                continue;
            }

            MetadataDbPropertySymbol propertySymbol = new(ownerField, property, result);
            ownerField.DeclareDbProperty(propertySymbol);
        }
    }


    public static AnalysisBlock BindBlockNodes(WorkFolder workFolder, Block block, string? context, string? language,
        string? labelType)
    {
        MetadataBinder binder = new(workFolder);
        binder.SetContext(context ?? string.Empty, language ?? string.Empty, labelType ?? string.Empty);
        AnalysisBlock boundNode = AnalysisNodeFactory.Block(block, null, null);
        // 遍历子节点
        foreach (var statement in block.Statements)
        {
            boundNode.AddChild(binder.BindMetadataNode(statement));
        }

        return boundNode;
    }


    protected override AnalysisTree BindTreeCore(SyntaxTree syntaxTree)
    {
        _currentTree = WorkFolder.GetAnalysisTree(syntaxTree);
        _treeSymbolTable = _currentTree.Symbols;

        // 记录当前的上下文配置
        string backupContext = _docContext;
        string backupLanguage = _docLanguage;
        string backupLabelType = _docLabelType;

        // 如果语法树根目录只有一个节点并且是Metadata Section，
        // 使用Metadata Section的子节点。
        IReadOnlyList<Statement> nodes = syntaxTree.GetNodes();
        if (nodes.Count > 0 &&
            nodes[0].Is<MetadataSection>(SyntaxKinds.MetadataSection, out MetadataSection? section))
        {
            if (!StringLiteral.IsDefaultOrEmpty(section.UserContext))
            {
                _docContext = section.UserContext.Value;
            }

            if (!StringLiteral.IsDefaultOrEmpty(section.LanguageName))
            {
                _docLanguage = section.LanguageName.Value;
            }

            if (!StringLiteral.IsDefaultOrEmpty(section.LabelType))
            {
                _docLabelType = section.LabelType.Value;
            }

            nodes = section.Body.Statements;
        }

        nodes.ForEach(stat => _currentTree.AddChild(BindMetadataNode(stat)));

        _docContext = backupContext;
        _docLanguage = backupLanguage;
        _docLabelType = backupLabelType;

        _treeSymbolTable = null;
        return _currentTree;
    }


    private bool DeclareSymbolToTree(ISymbol symbol)
    {
        Debug.Assert(_treeSymbolTable != null);
        return _treeSymbolTable.DeclareSymbol(symbol);
    }


    private ISymbol? LookupFieldSymbol(string name, bool fromTopLevel)
    {
        if (!fromTopLevel)
        {
            return _currentFieldDomain?.LookupLocalSymbol(name, true) ??
                   _treeSymbolTable?.LookupLocalSymbol(name);
        }

        ISymbol? result = _treeSymbolTable?.LookupLocalSymbol(name);

        if (result != null)
        {
            return result;
        }

        if (_currentFieldDomain == null)
        {
            return null;
        }

        Stack<ReadOnlySymbolTable> tableStack = new();
        tableStack.Push(_currentFieldDomain);
        ReadOnlySymbolTable? parentTable = _currentFieldDomain.Parent;
        while (parentTable is not null)
        {
            tableStack.Push(parentTable);
            parentTable = parentTable.Parent;
        }

        // 从栈顶开始查找
        while (tableStack.TryPop(out ReadOnlySymbolTable? table))
        {
            result = table.LookupLocalSymbol(name);
            if (result != null)
            {
                return result;
            }
        }

        return null;
    }


    private MetadataArealSymbol? LookupArealSymbol(string name)
    {
        Debug.Assert(_treeSymbolTable != null);
        return _treeSymbolTable.LookupLocalSymbol(name) as MetadataArealSymbol;
    }


    private ArealContext GetArealContext()
    {
        string context = _docContext;
        string language = _docLanguage;
        string labelType = _docLabelType;

        if (_currentAreal != null)
        {
            if (!string.IsNullOrEmpty(_currentAreal.Context))
            {
                context = _currentAreal.Context;
            }

            if (!string.IsNullOrEmpty(_currentAreal.Language))
            {
                language = _currentAreal.Language;
            }

            if (!string.IsNullOrEmpty(_currentAreal.LabelType))
            {
                labelType = _currentAreal.LabelType;
            }
        }

        return new ArealContext(context, language, labelType);
    }


    /// <summary>
    ///     绑定元数据使用lcl关键字定义区域标签，可以声明三种类型：UserContext，Language，LabelType。
    ///     声明的区域名在文件范围内不允许重复。
    /// </summary>
    private AnalysisMetadataArealDeclaration BindAreal(MetadataArealDeclaration areal, AnalysisNode? parent)
    {
        ArealContext context = GetArealContext();
        MetadataArealSymbol symbol = new(areal, context.Context, context.Language, context.LabelType);

        AnalysisMetadataArealDeclaration node = new(areal, parent);
        node.NameIdentifier.Bind(symbol);

        if (!DeclareSymbolToTree(symbol))
        {
            Raise(DiagnosticDescriptors.RepetitiveMetadataArealDefinition,
                areal.NameIdentifier, areal.Name);
        }

        return node;
    }


    private MetadataArealSymbol GetArealSymbol(MetadataArealSymbolTable symbolTable, IDeclaration declaration)
    {
        ArealContext context = GetArealContext();
        MetadataArealSymbol symbol = new(declaration, context.Context, context.Language, context.LabelType);
        // 对于Property、Template这类符号，允许重复声明，后声明的结果会替换掉之前的结果，此处不需要考虑是否成功。
        symbolTable.DeclareSymbol(symbol);
        return symbol;
    }


    private AnalysisMetadataProperty BindProperty(
        MetadataArealSymbolTable symbolTable,
        MetadataProperty property,
        AnalysisNode? parent)
    {
        MetadataArealSymbol symbol = GetArealSymbol(symbolTable, property);
        AnalysisMetadataProperty node = new(property, parent);
        node.NameIdentifier.Bind(symbol);
        return node;
    }


    private AnalysisMetadataTemplate BindTemplate(
        MetadataArealSymbolTable symbolTable,
        MetadataTemplate template,
        AnalysisNode? parent)
    {
        MetadataArealSymbol symbol = GetArealSymbol(symbolTable, template);
        AnalysisMetadataTemplate node = new(template, parent);
        node.NameIdentifier.Bind(symbol);
        return node;
    }


    private AnalysisMetadataStyleProperty BindStyleProperty(
        MetadataArealSymbolTable symbolTable,
        MetadataStyleProperty property,
        AnalysisNode? parent)
    {
        MetadataArealSymbol symbol = GetArealSymbol(symbolTable, property);
        AnalysisMetadataStyleProperty node = new(property, parent);
        node.NameIdentifier.Bind(symbol);
        // Children
        property.GetProperties().ForEach(p =>
            node.AddChild(BindProperty(symbolTable, p, node)));

        return node;
    }


    private void BindArealName(AnalysisIdentifier arealName)
    {
        if (Identifier.IsDefaultOrEmpty(arealName.Syntax))
        {
            return;
        }

        MetadataArealSymbol? arealSymbol = LookupArealSymbol(arealName.Syntax.Value);

        if (arealSymbol == null)
        {
            Raise(DiagnosticDescriptors.UndefinedAreaName,
                arealName.Syntax, arealName.Syntax.Value);
        }
        else
        {
            _currentAreal = arealSymbol;
            arealName.Bind(arealSymbol);
        }
    }


    private void BindList<TAnalysis, TSyntax>(AnalysisMetadataListWithAreal<TAnalysis, TSyntax> target,
        MetadataArealSymbolTable symbolTable,
        MetadataListWithAreal<TSyntax> list,
        MetadataArealCreator<TAnalysis, TSyntax> creator)
        where TAnalysis : AnalysisMetadataNode
        where TSyntax : SyntaxNode
    {
        if (target.ArealNameIdentifier != null)
        {
            BindArealName(target.ArealNameIdentifier);
        }

        foreach (TSyntax? element in list)
        {
            TAnalysis item = creator(symbolTable, element, target);
            target.AddChild(item);
        }
    }


    private AnalysisMetadataProperties BindProperties(MetadataProperties properties,
        MetadataArealSymbolTable table)
    {
        AnalysisMetadataProperties node = new(properties, null);
        BindList(node, table, properties, BindProperty);
        return node;
    }


    private AnalysisMetadataTemplates BindTemplates(MetadataTemplates templates,
        MetadataArealSymbolTable table)
    {
        AnalysisMetadataTemplates node = new(templates, null);
        BindList(node, table, templates, BindTemplate);
        return node;
    }


    private AnalysisMetadataStyle BindStyle(MetadataStyle style,
        MetadataArealSymbolTable table)
    {
        AnalysisMetadataStyle node = new(style, null);
        BindList(node, table, style, BindStyleProperty);
        return node;
    }


    private void UpdateLabeledObject(MetadataLabeledObject labeledObject,
        MetadataLabeledObjectSymbol symbol,
        AnalysisMetadataDeclarationWithChildren targetNode)
    {
        _currentAreal = null;

        // Properties
        labeledObject.Properties.ForEach(properties =>
            targetNode.AddChild(BindProperties(properties, symbol.GetPropertySymbols())));

        // Templates
        labeledObject.Templates.ForEach(templates =>
            targetNode.AddChild(BindTemplates(templates, symbol.GetTemplateSymbols())));

        // Style
        labeledObject.Styles.ForEach(style =>
            targetNode.AddChild(BindStyle(style, symbol.GetStyleSymbols())));

        // LabelStyle
        labeledObject.LabelStyles.ForEach(labelStyle =>
            targetNode.AddChild(BindStyle(labelStyle, symbol.GetLabelStyleSymbols())));

        // Labels
        HashSet<string> existArealName = new(StringComparer.OrdinalIgnoreCase);
        // 检查是否有相同Areal下的多个标签
        labeledObject.Labels.ForEach(label =>
        {
            if (!Identifier.IsDefaultOrEmpty(label.AreaName))
            {
                AnalysisIdentifier arealName = AnalysisNodeFactory.Identifier(label.AreaName, null, null);
                BindArealName(arealName);
                targetNode.AddChild(arealName);
            }

            if (existArealName.Add(label.AreaName?.Value ?? string.Empty))
            {
                return;
            }

            Raise(DiagnosticDescriptors.RepetitiveArealLabel, label);
        });

        _currentAreal = null;
    }


    private AnalysisMetadataFieldReference BindFieldReference(MetadataFieldReference fieldReference,
        AnalysisNode? parent)
    {
        AnalysisMetadataFieldReference node = new(fieldReference, parent);

        if (Identifier.IsDefaultOrEmpty(fieldReference.NameIdentifier))
        {
            return node;
        }

        ISymbol? fieldSymbol = LookupFieldSymbol(fieldReference.Name, false);
        if (fieldSymbol == null)
        {
            Raise(DiagnosticDescriptors.UnknownMetadataField,
                fieldReference.NameIdentifier,
                fieldReference.Name);
        }
        else
        {
            node.NameIdentifier.Bind(fieldSymbol);
        }

        return node;
    }


    private AnalysisMetadataCategory? BindCategory(
        MetadataFieldSymbol containingField,
        MetadataCategory syntax,
        AnalysisNode? parent,
        Func<MetadataCategorySymbol, bool> declare)
    {
        Identifier name;
        // - 如果忽略了分类名，按顺序查找后缀和描述。
        //      1. 检查是否引用了列表
        //      2. 优先查找后缀，后缀中，other > multiplier > DK > NA > REF
        //      3. 检查当前上下文下是否后合规的描述，如果存在，替换为命名
        if (Identifier.IsDefaultOrEmpty(syntax.NameIdentifier))
        {
            // use list_name
            if (syntax.ListUsage != null &&
                !Identifier.IsDefaultOrEmpty(syntax.ListUsage.NameIdentifier))
            {
                name = syntax.ListUsage.NameIdentifier;
            }
            else
            {
                // Other > Multiplier > DK > NA > REF > Label
                ITextNode? keywordToken =
                    syntax.Other?.DeclareKeywordToken ??
                    syntax.Multiplier?.DeclareKeywordToken ??
                    syntax.DkKeywordToken ??
                    syntax.NaKeywordToken ??
                    syntax.RefKeywordToken;

                if (keywordToken != null)
                {
                    name = NodeConverter.ToIdentifier((SyntaxToken)keywordToken);
                }
                // Label
                else
                {
                    StringLiteral? firstLabel =
                        (from label in syntax.Labels
                            where !StringLiteral.IsDefaultOrEmpty(label.LabelText)
                            select label.LabelText).FirstOrDefault();

                    if (firstLabel == null)
                    {
                        Raise(DiagnosticDescriptors.MissingCategoryName, syntax);
                        return null;
                    }

                    if (!StringHelper.IsValidIdentifier(firstLabel.Value))
                    {
                        Raise(DiagnosticDescriptors.InvalidMetadataName, firstLabel, firstLabel.Value);
                        return null;
                    }

                    name = NodeConverter.ToIdentifier(firstLabel, null);
                }
            }
        }
        else
        {
            name = syntax.NameIdentifier;
        }

        MetadataCategorySymbol symbol = new(containingField, syntax, name.Value);
        AnalysisMetadataCategory node = new(syntax, parent);
        node.NameIdentifier.Bind(symbol);

        UpdateLabeledObject(syntax, symbol, node);

        // use list_name
        if (syntax.ListUsage != null &&
            !Identifier.IsDefaultOrEmpty(syntax.ListUsage.NameIdentifier))
        {
            AnalysisMetadataListUsage listUsage = new(syntax.ListUsage, node);
            node.AddChild(listUsage);

            ISymbol? listSymbol = LookupFieldSymbol(syntax.ListUsage.Name,
                syntax.ListUsage.TopLevelOperatorToken != null);
            // 未找到时，报告错误
            // 元数据中，定义的顺序很重要，在列表引用时没有定义，视为没有找到定义
            if (listSymbol == null)
            {
                Raise(DiagnosticDescriptors.UndefinedMetadataElementList,
                    syntax.ListUsage.NameIdentifier, syntax.ListUsage.Name);
            }
            else
            {
                listUsage.NameIdentifier.Bind(listSymbol);
            }
        }

        // sub categories
        if (syntax.Categories != null)
        {
            bool withNamespace = syntax.Categories.NamespaceKeywordToken != null;
            // 如果带有namespace后缀，将列表中的符号声明到当前分类符号中，
            // 否则，将子列表中的符号声明到字段分类符号表中，此时，当前符号视为分组，
            // 不声明到符号表中
            if (withNamespace && !declare(symbol))
            {
                Raise(DiagnosticDescriptors.RepetitiveMetadataElementName,
                    name, symbol.Name);
            }

            foreach (MetadataCategory? category in syntax.Categories)
            {
                AnalysisMetadataCategory? subCategory = BindCategory(containingField, category, node,
                    withNamespace ? symbol.DeclareLocalCategory : containingField.DeclareCategory);
                // 只加入成功创建的节点
                if (subCategory != null)
                {
                    node.AddChild(subCategory);
                }
            }
        }

        // suffixes

        BindCategorySimpleSuffix(syntax.Factor);
        BindCategorySimpleSuffix(syntax.KeyCode);
        BindCategorySimpleSuffix(syntax.Expression);
        BindCategorySimpleSuffix(syntax.ElementType);

        BindFieldReferenceSuffix(syntax.Other);
        BindFieldReferenceSuffix(syntax.Multiplier);

        return node;

        void BindCategorySimpleSuffix(Declaration? declaration)
        {
            if (declaration == null)
            {
                return;
            }

            MetadataSuffixSymbol suffixSymbol = new(declaration);
            AnalysisMetadataSuffix suffixNode = new(declaration, node);
            suffixNode.NameIdentifier.Bind(suffixSymbol);
            node.AddChild(suffixNode);
            symbol.DeclareSuffix(suffixSymbol);
        }

        void BindFieldReferenceSuffix(MetadataFieldReferenceSuffix? declaration)
        {
            if (declaration == null)
            {
                return;
            }

            MetadataSuffixSymbol suffixSymbol = new(declaration);
            AnalysisMetadataSuffix suffixNode = new(declaration, node);
            suffixNode.NameIdentifier.Bind(suffixSymbol);

            if (declaration.Field != null)
            {
                suffixNode.AddChild(BindField(declaration.Field, containingField, node));
            }
            else if (declaration.Reference != null)
            {
                suffixNode.AddChild(BindFieldReference(declaration.Reference, node));
            }
        }
    }


    [GeneratedRegex(@"(?i:Filter|Weight|Multiplier|Coding|SourceFile|OtherSpecify|HelperField)")]
    private partial Regex GetUsageTypeRegex();


    private AnalysisMetadataField BindField(MetadataField field,
        MetadataFieldSymbol? containingField,
        AnalysisNode? parent)
    {
        MetadataFieldSymbol symbol = new(field, containingField);
        AnalysisMetadataField node = new(field, parent);
        node.NameIdentifier.Bind(symbol);

        bool declareResult = containingField?.DeclareNamedMember(symbol) ??
                             DeclareSymbolToTree(symbol);

        if (!declareResult)
        {
            Raise(DiagnosticDescriptors.RepetitiveMetadataFieldName, field.NameIdentifier, field.Name);
        }

        DomainSymbolTable? backupDomain = _currentFieldDomain;
        _currentFieldDomain = symbol.FieldSymbols;

        // LabeledObject
        UpdateLabeledObject(field, symbol, node);

        // Db properties
        if (field.IsDbField)
        {
            // Column
            if (field.DbProperties.Columns != null)
            {
                CheckDbProperties(symbol, field.DbProperties.Columns, EffectiveDbColumnProperties);
            }

            // Properties
            CheckDbProperties(symbol, field.DbProperties, EffectiveDbProperties);
        }

        // Categories
        field.Categories?.ForEach(category =>
            BindCategory(symbol, category, node, symbol.DeclareCategory));

        // Class
        if (field.Class != null)
        {
            Debug.Assert(symbol.Class != null);
            node.AddChild(BindClass(field.Class, symbol, symbol.Class, node));
        }

        // Page Items
        if (field.IsPage)
        {
            field.GetPageItems().ForEach(identifier =>
            {
                if (LookupFieldSymbol(identifier.Value, true) is not MetadataFieldSymbol refField)
                {
                    Raise(DiagnosticDescriptors.UnknownMetadataField, identifier, identifier.Value);
                }
                // 不允许页面引用ElementList
                else if (refField.FieldKind == MetadataFieldKind.ElementList)
                {
                    Raise(DiagnosticDescriptors.NameIsNotAField, identifier, identifier.Value);
                }
                else
                {
                    AnalysisIdentifier analysisId = AnalysisNodeFactory.Identifier(identifier, node, null);
                    analysisId.Bind(refField);
                    node.AddChild(analysisId);
                }
            });
        }

        // Suffix
        BindFieldSuffix(field.Axis);
        BindFieldSuffix(field.Expression);
        BindFieldSuffix(field.Precision);
        BindFieldSuffix(field.Validation);
        BindFieldSuffix(field.Scale);
        BindFieldSuffix(field.DefaultAnswer);
        BindFieldSuffix(field.InitialAnswer);

        // UsageType
        BindFieldSuffix(field.UsageType);
        // Filter,Weight,Multiplier,Coding,SourceFile,OtherSpecify,HelperField
        if (!StringLiteral.IsDefaultOrEmpty(field.UsageType?.Argument))
        {
            string[] types = field.UsageType.Argument.Value.Split(',');
            List<string> unmatchedUsageType =
                (from typeName in types
                    let trimmedTypeName = typeName.Trim()
                    where !GetUsageTypeRegex().IsMatch(trimmedTypeName)
                    select typeName).ToList();

            if (unmatchedUsageType.Count > 0)
            {
                Raise(DiagnosticDescriptors.UnknownSpecialUsageType, field.UsageType.Argument,
                    string.Join(',', unmatchedUsageType));
            }
        }

        // Row,Column
        if (field is { RowKeywordToken: not null })
        {
            // 如果column关键字在row关键字之前，也一并忽略
            if (field.ColumnKeywordToken != null && field.ColumnKeywordToken.End < field.RowKeywordToken.Start)
            {
                Raise(DiagnosticDescriptors.IneffectiveToken, field.ColumnKeywordToken,
                    "column");
            }

            Raise(DiagnosticDescriptors.CanBeOmitted, field.RowKeywordToken, "row");
        }

        // Grid 应当替换为 loop
        if (field.DeclareKeywordToken.IsNode(SyntaxKinds.GridKeywordToken))
        {
            Raise(DiagnosticDescriptors.ReplaceGridToLoop, field.DeclareKeywordToken);
        }

        // Codes
        if (field.Codes != null)
        {
            // Codes在存储时会单独生成一个字段，和当前字段中的分类列表不冲突
            AnalysisMetadataSuffix codesNode = new(field.Codes, node);
            MetadataFieldSymbol codesSymbol = new(field.Codes, symbol);
            // use field_name
            if (field.Codes.FieldReference != null)
            {
                node.AddChild(BindFieldReference(field.Codes.FieldReference, node));
            }
            else
            {
                field.Codes.Categories?.ForEach(code =>
                    BindCategory(codesSymbol, code, node, codesSymbol.DeclareCategory));
            }

            codesNode.NameIdentifier.Bind(codesSymbol);
            node.AddChild(codesNode);
        }

        // helper-fields
        if (field.HelperFields != null)
        {
            MetadataSuffixSymbol helperFieldsSymbol = new(field.HelperFields);
            AnalysisMetadataSuffix helperFieldsNode = new(field.HelperFields, node);
            node.AddChild(helperFieldsNode);
            helperFieldsNode.NameIdentifier.Bind(helperFieldsSymbol);

            field.HelperFields.ForEach(fieldOrReference =>
            {
                // Reference
                if (fieldOrReference.IsFieldReference)
                {
                    helperFieldsNode.AddChild(BindFieldReference(fieldOrReference.Reference, helperFieldsNode));
                }
                else if (fieldOrReference.IsField)
                {
                    helperFieldsNode.AddChild(BindField(fieldOrReference.Field, symbol, helperFieldsNode));
                }
            });
        }

        _currentFieldDomain = backupDomain;

        return node;

        void BindFieldSuffix<T>(MetadataSingleArgumentSuffix<T>? declaration)
            where T : Expression
        {
            if (declaration == null)
            {
                return;
            }

            MetadataSuffixSymbol suffixSymbol = new(declaration);
            AnalysisMetadataSuffix suffixNode = new(declaration, node);
            node.NameIdentifier.Bind(suffixSymbol);
            node.AddChild(suffixNode);
            symbol.DeclareSuffix(suffixSymbol);
        }
    }


    private AnalysisMetadataClass BindClass(MetadataClass syntax,
        MetadataFieldSymbol containingField,
        MetadataClassSymbol classSymbol,
        AnalysisNode? parent)
    {
        AnalysisMetadataClass node = new(syntax, parent);
        node.NameIdentifier.Bind(classSymbol);

        // LabeledObject
        UpdateLabeledObject(syntax, classSymbol, node);

        // Fields
        syntax.ForEach(field => node.AddChild(BindField(field, containingField, node)));

        return node;
    }


    private AnalysisNode BindMetadataNode(Statement node)
    {
        return node switch
        {
            { Kind: SyntaxKinds.MetadataAreaName } => BindAreal((MetadataArealDeclaration)node, null),
            { Kind: SyntaxKinds.MetadataField } => BindField((MetadataField)node, null, null),
            // 非法符号的错误应当在扫描时报告
            _ => AnalysisEmptyStatement.Default
        };
    }


    private record ArealContext(string Context, string Language, string LabelType);


    private delegate TAnalysis MetadataArealCreator<out TAnalysis, in TSyntax>(
        MetadataArealSymbolTable symbolTable,
        TSyntax syntax,
        AnalysisNode? parent);
}